package queue

import "errors"

type ArrQueueV2 struct {
	size     int
	capacity int
	Data     []any
	front    int
}

func NewArrQueueV2(capacity int) *ArrQueueV2 {
	return &ArrQueueV2{
		size:     0,
		capacity: capacity,
		Data:     make([]any, capacity),
	}
}

func (a *ArrQueueV2) Size() int {
	return a.size
}

func (a *ArrQueueV2) Capacity() int {
	return a.capacity
}

func (a *ArrQueueV2) Index(index int) int {
	return (index + a.capacity) % a.capacity
}

func (a *ArrQueueV2) PushFirst(val any) error {
	if a.size == a.capacity {
		return errors.New("failure: capacity is full")
	}

	a.front = a.Index(a.front - 1)
	a.Data[a.front] = val
	a.size++
	return nil
}

func (a *ArrQueueV2) PushLast(val any) error {
	if a.size == a.capacity {
		return errors.New("failure: capacity is full")
	}

	a.front = a.Index(a.front + a.size)
	a.Data[a.front] = val
	a.size++
	return nil
}

func (a *ArrQueueV2) IsEmpty() bool {
	return a.size <= 0
}

func (a *ArrQueueV2) PopFirst() any {
	if a.size <= 0 {
		return nil
	}

	val := a.PeekFirst()
	a.front = a.Index(a.front + 1)
	a.size--

	return val
}

func (a *ArrQueueV2) PopLast() any {
	if a.size <= 0 {
		return nil
	}

	val := a.PeekLast()
	a.size--
	return val
}

func (a *ArrQueueV2) PeekFirst() any {
	if a.IsEmpty() {
		return nil
	}

	return a.Data[a.front]
}

func (a *ArrQueueV2) PeekLast() any {
	if a.IsEmpty() {
		return nil
	}
	last := a.Index(a.front + a.size - 1)
	return a.Data[last]
}
